package br.edu.unifei.cct720.trabalho05.principal.controlador;

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseListener;
import java.awt.font.NumericShaper;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JCheckBox;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import org.w3c.dom.events.EventTarget;
import org.w3c.dom.events.MouseEvent;
import org.w3c.dom.views.AbstractView;

import br.edu.unifei.cct720.trabalho05.eventos.MyActionListener;
import br.edu.unifei.cct720.trabalho05.principal.gui.JanelaPrincipal;
import br.edu.unifei.cct720.trabalho05.padroes.Controlador;
import br.edu.unifei.cct720.trabalho05.utils.constantes.Constantes;
import br.edu.unifei.cct720.trabalho05.utils.constantes.Mensagem;
import br.edu.unifei.cct720.trabalho05.utils.formas.Circulo;
import br.edu.unifei.cct720.trabalho05.utils.formas.FormaGeometrica;
import br.edu.unifei.cct720.trabalho05.utils.formas.Retangulo;
import br.edu.unifei.cct720.trabalho05.utils.formas.Setor;
import br.edu.unifei.cct720.trabalho05.utils.ponto.Ponto;
import br.edu.unifei.cct720.trabalho05.utils.ponto.Pontos;
import br.edu.unifei.cct720.trabalho05.utils.sombreamento.Sombreamento;

/**
 * Classe responsavel por intermediar as interacoes do usuario
 * com o restante do programa
 * 
 * @author fknappe
 *
 */
public class ControladorPrincipal extends Controlador {

	// Declaracao das variaveis de instancia
	private String forma = "";
	private List<String> sombreamentos = null;

	/**
	 * Construtor 
	 * 
	 * @param JanelaPrincipal j
	 */
	public ControladorPrincipal(JanelaPrincipal j) {
		super(j);
		sombreamentos = new ArrayList<String>();
	}

	/**
	 * Metodo responsavel por registrar todas as acoes
	 * dos componentes da GUI
	 */
	@Override
	public void registraEventos() {

		// Instanciando um novo listener
		MyActionListener myListener = new MyActionListener();

		/*
		 *  Adicionando o tratamento de acoes aos componentes da GUI
		 */
		this.frame.getBtnSair().addActionListener(myListener);
		this.frame.getBtnSobre().addActionListener(myListener);
		this.frame.getBtnDesenhar().addActionListener(myListener);
		this.frame.getBtnLimpar().addActionListener(myListener);

		/*
		 * Adicionando tratamento para selecao das formas
		 */
		this.frame.getCmbFormas().addActionListener(new ActionListener(){

			@Override
			public void actionPerformed(ActionEvent e) {
				forma = (String)frame.getCmbFormas().getSelectedItem();
				frame.getBtnLimpar().setEnabled(true);
				habilitarMenuSombreamentos();
			}
		});

		/*
		 * Adicionando tratamento para selecao dos sombreamentos disponiveis 
		 */
		for(JCheckBox c : this.frame.getPanelMenuSombreamento().getCheckSombreamentos()) {
			c.addActionListener(new ActionListener() {

				@Override
				public void actionPerformed(ActionEvent e) {
					JCheckBox cb = (JCheckBox)e.getSource();
					if(cb.isSelected()) {
						if(!sombreamentos.contains(cb.getText())) {
							sombreamentos.add(cb.getText());
							habilitarMenuFormas();
						}
					} else{
						if(sombreamentos.contains(cb.getText())) {
							sombreamentos.remove(cb.getText());
							habilitarMenuFormas();
						}
					}
				}
			});
		}
	}

	public void desenhar() {
		// Limpa todas as acoes anteriores da area de desenho
		this.frame.getPanelDesenho().setFormas(new ArrayList<Pontos>());
		
		try{ 
			// Chamada para construcao da forma geometrica
			FormaGeometrica forma = constroiForma();

			//Adiciona a forma ao painel de desenho
			this.frame.getPanelDesenho().addForma(forma.getPontos());

			//Obtem o valor do fator de sombreamento
			double fator =
					Mensagem.entradaDeDadosDouble(
							"Determine o valor do fator de espacamento: "
					);

			// Instancia um novo sombreamento
			Sombreamento sombreamento = new Sombreamento();
			for(String tipoSombreamento : sombreamentos) {
				this.frame.getPanelDesenho().addForma(
						sombreamento.criaSombreamento(
								forma, 
								tipoSombreamento, 
								fator
						)
				);
			}

			// Apresenta o objeto na area de desenho
			this.frame.getPanelDesenho().repaint();

		} catch(NumberFormatException e) {
			e.printStackTrace();
			Mensagem.mostraErro(
					this.frame, 
					"Valores fornecido pelo usuario invalido. Tente novamente."
			);
		} finally{

		}
	}

	/**
	 * Metodo responsavel por reinicializar o estado da interface para
	 * default
	 * 
	 * @return void
	 */
	public void limpar() {
		this.frame.getPanelDesenho().setFormas(new ArrayList<Pontos>());
		this.frame.getCmbFormas().setSelectedIndex(-1);
		this.frame.getBtnDesenhar().setEnabled(false);
		this.frame.getBtnLimpar().setEnabled(false);
		this.frame.getPanelMenuSombreamento().desabilitarFuncoes();
		this.frame.getPanelDesenho().repaint();
	}

	/**
	 * Metodo responsavel por tratar as acoes do botao que mostra as informacoes
	 * sobre o(s) autor(es) deste projeto
	 * 
	 * @return void
	 */
	public void sobre() {
		Mensagem.mostraMensagemSobre(
				this.frame,
				"Universidade Federal de Itajuba\n" + 
				"CCT 720 - Computacao Grafica II \n" +
				"Professor: Dr. Edison Oliveira de Jesus\n" +
				"Aluno: Felipe Agostini Knappe - 12623"
		);
	}

	/**
	 * Metodo responsavel por tratar as acoes do botao de finalizar o aplicativo
	 * 
	 * @return void
	 */
	public void sair() {
		if(Mensagem.confirmaMensagem(
				this.frame, 
				"Deseja realmente sair do programa?"
		)
		) {
			this.frame.dispose();
			System.exit(0);
		}
	}

/* ****************************************************************************************************************************************************************
 * 															Metodos auxiliares (privados)
 ******************************************************************************************************************************************************************/
	
	/**
	 * Metodo responsavel por habilitar as acoes
	 * do menu de selecao das formas geometricas
	 * 
	 * @return void
	 */
	private void habilitarMenuFormas() {
		if(this.sombreamentos.size() > 0) {
			this.frame.getBtnDesenhar().setEnabled(true);
		} else {
			this.frame.getBtnDesenhar().setEnabled(false);
		}
	}

	/**
	 * Metodo responsavel por habilitar as acoes
	 * do menu de selecao do tipo de sombreamento
	 * 
	 * @return void
	 */
	private void habilitarMenuSombreamentos() {
		this.frame.getPanelMenuSombreamento().desabilitarFuncoes();
		if(forma == Constantes.RETANGULO) {
			this.frame.getPanelMenuSombreamento().habilitaFuncoes(
					Constantes.TIPOS_SOMBREAMENTO_RETANGULO	
			);
		} else {
			this.frame.getPanelMenuSombreamento().habilitaFuncoes(
					Constantes.TIPOS_SOMBREAMENTO_SETOR	
			);
		}
	}

	/**
	 * Metodo responsavel por construir uma forma geometrica
	 * de acordo com o tipo especificado pelo usuario na 
	 * interface
	 * 
	 * @return void
	 * @throws NumberFormatException
	 */
	private FormaGeometrica constroiForma() throws NumberFormatException {
		if(forma == Constantes.RETANGULO) {
			return this.constroiRetangulo();
		} else if(forma == Constantes.CIRCULO) {
			return this.constroiCirculo();
		} else
			return this.constroiSetor();
	}

	/**
	 * Metodo responsavel por construir um retangulo de acordo com os
	 * parametros definidos pelo usuario
	 * 
	 * @return Retangulo
	 * @throws NumberFormatException
	 */
	private Retangulo constroiRetangulo() throws NumberFormatException {
		return new Retangulo(
				new Ponto(
						Mensagem.entradaDeDadosInteiros("Digite o valor da coordenada X do ponto superior esquerdo: "),
						Mensagem.entradaDeDadosInteiros("Digite o valor da coordenada Y do ponto superior esquerdo: "),
						Color.BLACK
				),
				new Ponto(	
						Mensagem.entradaDeDadosInteiros("Digite o valor da coordenada X do ponto inferior direito: "),
						Mensagem.entradaDeDadosInteiros("Digite o valor da coordenada Y do ponto inferior direito: "),
						Color.BLACK
				),
				Color.BLACK
		);
	}

	/**
	 * Metodo responsavel por construir um circulo, de acordo com
	 * os parametros definidos pelo usuario
	 * 
	 * @return Setor
	 * @throws NumberFormatException
	 */
	private Setor constroiCirculo() throws NumberFormatException {
		return new Setor(
				new Ponto(
						Mensagem.entradaDeDadosInteiros("Digite o valor da coordenada X do centro: "),
						Mensagem.entradaDeDadosInteiros("Digite o valor da coordenada Y do centro: "),
						Color.black
				),
				Mensagem.entradaDeDadosInteiros("Digite o valor do raio: "),
				0, 360,
				Color.BLACK
		);
	}

	/**
	 * Metodo responsavel por construir um setor, de acordo com os
	 * parametros definidos pelo usuario
	 * 
	 * @return Setor
	 * @throws NumberFormatException
	 */
	private Setor constroiSetor() throws NumberFormatException {
		return new Setor(
				new Ponto(
						Mensagem.entradaDeDadosInteiros("Digite o valor da coordenada X do centro: "),
						Mensagem.entradaDeDadosInteiros("Digite o valor da coordenada Y do centro: "),
						Color.black
				),
				Mensagem.entradaDeDadosInteiros("Digite o valor do raio: "),
				Mensagem.entradaDeDadosInteiros("Digite o valor do angulo inicial: "),
				Mensagem.entradaDeDadosInteiros("Digite o valor do angulo final: "),
				Color.BLACK
		);
	}
}
